package com.llmm.controller;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

/**
 * @description: 文件分块上传
 * @author: llmm
 * @date: 2022/5/21
 */
@RestController
@RequestMapping("largeFile")
public class UploadController {

    private final static String utf8="utf-8";

    @PostMapping("upload")
    public void uploadFiles(HttpServletRequest request, HttpServletResponse response){

        // 分片操作。
        response.setCharacterEncoding(utf8);
        // 当前分片
        Integer schunk=null;
        // 总分片
        Integer schunks=null;
        // 文件名
        String name =null;
        // 保存路径。
        String uploadPath = "E:\\workspace\\chunkFile";
        // 流输出。
        BufferedOutputStream bos =null;
        try {
            // 用于 设置一些参数
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 缓冲区
            factory.setSizeThreshold(1024);
            // 临时目录
            factory.setRepository(new File(uploadPath));
            // 用来解析request
            ServletFileUpload upload =new ServletFileUpload(factory);
            //现在文件大小，总大小(5M,10M)
            upload.setFileSizeMax(5l *1024l*1024l*1024l);
            upload.setSizeMax(10l *1024l*1024l*1024l);
            List<FileItem> items = upload.parseRequest(request);
            // 取到文件中非文件信息
            for (FileItem item : items) {
                // 判断是否时文件对象，true 非文件域，为表单域。
                if (item.isFormField()){
                    // 当前分片数。
                    if ("chunk".equals(item.getFieldName())){
                        schunk= Integer.parseInt(item.getString(utf8));
                    }
                    // 拿到分片数。
                    if ("chunks".equals(item.getFieldName())){
                        schunks= Integer.parseInt(item.getString(utf8));
                    }
                    // 文件名。
                    if ("name".equals(item.getFieldName())){
                        name= item.getString(utf8);
                    }
                }
            }
            // 取文件对象
            for (FileItem item:items){
                // 文件域
                if (!item.isFormField()){
                    String temFileName = name;
                    // 文件不能为空
                    if (name !=null){
                        // 如果为空，表示一个整文件。没有分片
                        if (schunk !=null){
                            temFileName=schunk+"_"+name;
                        }
                        //获取文件
                        File temFile =new File(uploadPath,temFileName);
                        // 断点续传 ，网络中断等原因，再一次上传，判断，分块文件不存在，才去传。
                        if (!temFile.exists()){
                            item.write(temFile);
                        }
                    }
                }
            }

            // 合并
            // 是否有分片,并且最后一个分片传递过来才合并。分片从0开始需-1.
            if (schunk !=null && schunk.intValue() == schunks.intValue()-1){
                File tempFile =new File(uploadPath,name);
                bos=new BufferedOutputStream(new FileOutputStream(tempFile));
                // 找文件。
                for (int i =0;i<schunks;i++){
                    File file=new File(uploadPath,i+"_"+name);
                    // 传导无顺序，保证每一个分片存在。
                    while (!file.exists()){
                        Thread.sleep(100);
                    }
                    byte[] bytes= FileUtils.readFileToByteArray(file);
                    bos.write(bytes);
                    bos.flush();
                    file.delete();
                }
                bos.flush();
            }
            response.getWriter().write("上传成功"+name);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try{
                if (bos!=null){
                    bos.close();
                }
            }catch (IOException e){
                 e.printStackTrace();
            }
        }

    }



}
